//
//  NSString+DDAdd.h
//  AFNetworking
//
//  Created by 许龙 on 2019/9/24.
//

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

typedef NS_ENUM(NSInteger, DDOperator) {
    DDOperatorAdd = 0,         // +
    DDOperatorSubtract,        // -
    DDOperatorMultiply,        // *
    DDOperatorDivide,          // /
    DDOperatorRaisingToPower,  // pow
    DDOperatorMultiplyingByPowerOf10 // * 10^pow
};

@interface NSString (DDAdd)

#pragma mark - Encode and decode

/**
URL encode a string in utf-8.
@return the encoded string.
*/
- (NSString *)stringByURLEncode;

/**
URL decode a string in utf-8.
@return the decoded string.
*/
- (NSString *)stringByURLDecode;

/**
Escape common HTML to Entity.
Example: "a>b" will be escape to "a&gt;b".
*/
- (NSString *)stringByEscapingHTML;

#pragma mark - Regular Expression

/**
Whether it can full match the regular expression

@param regex  The regular expression
@return YES if can match the regex; otherwise, NO.
*/
- (BOOL)fullMatchesRegex:(NSString *)regex;

/**
 Whether it can match the regular expression
 
 @param regex  The regular expression
 @param options     The matching options to report.
 @return YES if can match the regex; otherwise, NO.
 */
- (BOOL)matchesRegex:(NSString *)regex options:(NSRegularExpressionOptions)options;

/**
 Match the regular expression, and executes a given block using each object in the matches.
 
 @param regex    The regular expression
 @param options  The matching options to report.
 @param block    The block to apply to elements in the array of matches.
 The block takes four arguments:
     match: The match substring.
     matchRange: The matching options.
     stop: A reference to a Boolean value. The block can set the value
         to YES to stop further processing of the array. The stop
         argument is an out-only argument. You should only ever set
         this Boolean to YES within the Block.
 */
- (void)enumerateRegexMatches:(NSString *)regex
                      options:(NSRegularExpressionOptions)options
                   usingBlock:(void (^)(NSString *match, NSRange matchRange, BOOL *stop))block;

/**
 @"1.001" will Returns YES, @"xxxx" Returns NO
 */
- (BOOL)isNumber;

/**
 Check whether it is Chinese or not
 */
- (BOOL)isChinese;

#pragma mark - Drawing

/**
 Returns the size of the string if it were rendered with the specified constraints.
 
 @param font          The font to use for computing the string size.
 
 @param size          The maximum acceptable size for the string. This value is
 used to calculate where line breaks and wrapping would occur.
 
 @param lineBreakMode The line break options for computing the size of the string.
 For a list of possible values, see NSLineBreakMode.
 
 @return              The width and height of the resulting string's bounding box.
 These values may be rounded up to the nearest whole number.
 */
- (CGSize)sizeForFont:(UIFont *)font size:(CGSize)size mode:(NSLineBreakMode)lineBreakMode;

/**
 Returns the width of the string if it were to be rendered with the specified
 font on a single line.
 
 @param font  The font to use for computing the string width.
 
 @return      The width of the resulting string's bounding box. These values may be
 rounded up to the nearest whole number.
 */
- (CGFloat)widthForFont:(UIFont *)font;

/**
 Returns the height of the string if it were rendered with the specified constraints.
 
 @param font   The font to use for computing the string size.
 
 @param width  The maximum acceptable width for the string. This value is used
 to calculate where line breaks and wrapping would occur.
 
 @return       The height of the resulting string's bounding box. These values
 may be rounded up to the nearest whole number.
 */
- (CGFloat)heightForFont:(UIFont *)font width:(CGFloat)width;

/**
Trim blank characters (space and newline) in head and tail.
@return the trimmed string.
*/
- (NSString *)stringByTrim;

/**
 nil, @"", @"  ", @"\n" will Returns NO; otherwise Returns YES.
 */
- (BOOL)isNotBlank;

/**
Returns YES if the target string is contained within the receiver.
@param string A string to test the the receiver.

@discussion Apple has implemented this method in iOS8.
*/
- (BOOL)containsString:(NSString *)string;

/**
 Returns an NSDictionary/NSArray which is decoded from receiver.
 Returns nil if an error occurs.
 
 e.g. NSString: @"{"name":"a","count":2}"  => NSDictionary: @[@"name":@"a",@"count":@2]
 */
- (nullable id)jsonValueDecoded;

/**
 Returns NSMakeRange(0, self.length).
 */
- (NSRange)rangeOfAll;

/**
 Returns an NSData using UTF-8 encoding.
 */
- (nullable NSData *)dataValue;

#pragma mark - Number

/**
 Try to parse this string and returns an `NSNumber`.
 @return Returns an `NSNumber` if parse succeed, or nil if an error occurs.
 */
- (nullable NSNumber *)numberValue;

/**
 Returns the effective decimal digit if it is a number.
 
 @discussion "1.10" will return 1
 Returns -1 when it is not a number
 */
- (NSInteger)decimalDigit;

/**
 Format decimal numbers and make decimal numbers, NSRoundingMode default is Plain.
 @param digit decimal digit
 
 @return Returns nil if the string is not a number.
 */
- (nullable NSString *)stringWithDecimalDigit:(NSUInteger)digit;

/**
 Format decimal numbers and make decimal numbers
 @param digit decimal digit
 
 @discussion Rounding policies :
 Original
 value   1.2 1.21 1.25 1.35 1.27
 Plain   1.2 1.2  1.3  1.4  1.3
 Down    1.2 1.2  1.2  1.3  1.2
 Up      1.2 1.3  1.3  1.4  1.3
 Bankers 1.2 1.2  1.2  1.4  1.3
 
 @return Returns nil if the string is not a number.
  */
- (nullable NSString *)stringWithDecimalDigit:(NSUInteger)digit mode:(NSRoundingMode)mode;

#pragma mark - Calculate

/**
 Calculate with "+", "-", "*", "/"
 @param value right operation value
 @param op operator
 @param digit decimal digit
 @param mode Plain Down Up Bankers
 
 @return Returns nil if the string is not a number.
 */
- (nullable NSString *)stringNumberByValue:(NSString *)value
                                        op:(DDOperator)op
                                     digit:(NSUInteger)digit
                                     model:(NSRoundingMode)mode;

/**
 Compare with the string number
 
 @discussion
 NSOrderedAscending：less
 NSOrderedDescending：more
 */
- (NSComparisonResult)stringNumberCompare:(NSString *)value;


/**
 1,000 one thousand
 1,000,000 one million
 1,000,000,000 one billion
*/
- (NSString *)stringByDelimiter;


/**
 向下取整和向上取整
 用户交易价格范围计算
 */
- (nullable NSString *)stringWithDecimalDigit:(NSUInteger)digit up:(BOOL)up;

@end

NS_ASSUME_NONNULL_END
